"use strict";
(function(host){

var mvc = host.mvc;

var LAYERS = {};
mvc.createView = function(conf, id){
	if(conf && util.isString(conf)){
		conf = { el: { name: conf } };
	}
	conf = conf && util.isObject(conf) ? conf : {};
	var view = new mvc.core.View(conf.el, conf.type, id);
	var cssHost;
	if(!conf.create_rule){
		cssHost = view.element;
	} else {
		var uniqCls = view.$getCssName();
		cssHost = mvc.addGlobalRule('.' + uniqCls);
		view.addClass(uniqCls);
	}
	view.$cssHost = function(){
		return cssHost;
	};
	return view;
};
mvc.createV = mvc.createView;

mvc.createController = function(schema){
	var methods = {
		setter : (function(){}).bind(R),
		disabled : false
	};
	var view = null;
	var ctrl = new mvc.core.SchemaController(schema);
	
	ctrl.listen = function(view, key, val, oldVal){
		if(methods.disabled) return;
		methods.setter(view, key, val, oldVal);
	};
	
	function viewReturn(){ return view; };

	var R = {
		bind: function(model){
			if(model instanceof mvc.core.Model){
				model.bind(ctrl.schema, ctrl, viewReturn);
			}
		},
		unbind: function(model){
			model.unbind(ctrl.schema, function(tar){
				return tar[0] === ctrl && tar[1] === viewReturn;
			});
		},
		attach: function(v){
			this.detach();
			if(v && v instanceof mvc.core.View){
				view = v;
				methods.disabled = false;
			}
		},
		detach: function(){
			view = null;
			methods.disabled = true;
		},
		defineGetter: function(fn, ctx){
			if(util.isFunction(fn)) methods.getter = fn.bind(ctx);
		},
		defineSetter: function(fn, ctx){
			if(util.isFunction(fn)) methods.setter = fn.bind(ctx);
		},
		valueOf: function(){
			return ctrl;
		}
	};
	return R;
};
mvc.createC = mvc.createController;

mvc.createModelController = function(schema, data){
	var args = Array.prototype.slice.call(arguments, 0);
	var schema, data;
	if(util.isObject(args[0])){
		data = args.shift();
		schema = args;
	} else if(util.isArray(args[0])) {
		schema = args.shift();
		data = args[0];
	} else {
		schema = args;
		data = {};
	}
	if(!util.isObject(data)) data = {};

	var ctrl = mvc.createController(schema);
	var model = new mvc.core.Model(data);

	ctrl.bind(model);

	var R = {
		attach: function(target){
			ctrl.attach(target);
			// model.bind(schema, ctrl.valueOf(), target);
		},
		detach: function(){
			ctrl.detach();
			// model.unbind(schema, ctrl.valueOf());
		},
		defineSetter: function(fn, ctx){
			ctrl.defineSetter(fn, ctx);
		},
		defineGetter: function(key, fn){
			model.defineGetter(key, fn);
		},
		set: function(key, value, noTell){
			model.set(key, value, noTell);
		},
		get: function(key){
			return model.get(key);
		},
		valueOf: function(){
			return model;
		}
	};
	return R;
}
mvc.createMC = mvc.createModelController;

mvc.layer = {
	create: function(conf, schema, data){
		var args = Array.prototype.slice.call(arguments, 1);
		var mc = mvc.createModelController.apply(this, args);
		var view = mvc.createView(conf);

		var cssHost = view.$cssHost();
		var R = {
			defineSetter: function(fn){
				mc.defineSetter(fn, this);
				return this;
			},
			defineGetter: function(key, fn){
				mc.defineGetter(key, fn);
				return this;
			},
			set: function(key, value, noTell){
				mc.set(key, value, noTell);
				return this;
			},
			get: function(key){
				return mc.get(key);
			},
			css: function(o, v){
				util.obj2style(cssHost.style, o, v);
				return this;
			},
			addElement: function(domConf){
				var el = mvc.createElement(domConf);
				return el;
			},
			addView: function(conf){
				var v = mvc.createView(conf, view.$id());
				view.append(v);
				return v;
			},
			valueOf: function(){
				return mc.valueOf();
			}
		};
		util.EACH(
			['append', 'appendTo', 'addClass', 'removeClass', 'clearClass', 'attr'],
			function(key){
				R[key] = function(){
					view[key].apply(view, arguments);
					return this;
				};
			}
		);
		mc.attach(view);
		return LAYERS[view.__id] = R;
	},
	css: function(conf, schema, data){
		var R = this.create(conf, schema);
		R.defineSetter(function(view, key, value){
			this.css(key, value);
		});
		return R;
	},
	rect: function(conf){
		var schema = ['left', 'top', 'width', 'height'];
		var R = this.css(conf, schema);
		R.defineGetter(schema, function(v, key){
			v = v || 0;
			if(isNaN(v)) v = 0;
			switch(key){
				case 'width':
				case 'height':
					v = Math.max(0, v || 0);
					break;
			}
			return v;
		});
		schema.forEach(function(key){
			R[key] = function(v){
				if(arguments.length < 1) return this.get(key);
				this.set(key, v);
				return this;
			};
		});
		R.xy = function(x, y){
			if(arguments.length < 1){
				return {
					x: this.get('left'),
					y: this.get('top')
				};
			} else if(arguments.length == 1 && util.isObject(x)){
				return this.xy(x.left, x.top);
			}
			this.set('left', x);
			this.set('top', y);
			return this;
		};
		R.size = function(w, h){
			if(arguments.length < 1){
				return {
					width: this.get('width'),
					height: this.get('height')
				};
			} else if(arguments.length == 1 && util.isObject(w)){
				return this.size(w.width, w.height);
			}
			this.set('width', w);
			this.set('height', h);
			return this;
		}
		return R;
	}
};



mvc.findLayer = function(id){ return LAYERS[id] || null; };

})(window);